/**
 * 权限声明：
 */
package com.handy.webwork.action.result;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.handy.webwork.action.AbstractAction;
import com.handy.webwork.action.ActionForm;
import com.handy.webwork.action.ActionMapping;
import com.handy.webwork.action.ActionMessage;
import com.handy.webwork.action.ActionResult;
import com.handy.webwork.config.HandyConfiguration;

/**
 * 跳转。
 * 
 * @author rocken.zeng@gmail.com
 * 
 */
public class Forward {
	private static Log log = LogFactory.getLog(Forward.class);

	private HttpServletRequest request;
	private HttpServletResponse response;
	private ServletContext context;

	public Forward(HttpServletRequest request, HttpServletResponse response,
			ServletContext context) {
		this.request = request;
		this.response = response;
		if (log.isDebugEnabled()){
			log.info("视图：Forward转向。");
		}
	}

	/**
	 * 当result类型为forward时，将请求转发到指定控制器，所有bean值传入下个bean。
	 * 
	 * @param fAction
	 * @param fResult
	 * @param actionForm
	 * @param actionMessage
	 * @throws IOException
	 * @throws ServletException
	 */
	@SuppressWarnings("unchecked")
	public void doForward(AbstractAction fAction, ActionResult fResult,
			ActionForm actionForm, ActionMessage actionMessage) {
		ActionResult result = null;
		HashMap root = new HashMap();//所有forward共享一个map,这样可以实现所有froward期间的action由上到下传递参数.
		if (fAction.sendData() != null) {
			root.putAll(fAction.sendData());//将上一个action要传递的数据放入map中备用.
		}
		int i = 1;

		String actionName = fResult.getResultValue();//本次要执行的action
		if (actionName == null || actionName.equals(""))
			return;

		HashMap<String, String> params = handleParam(actionName, fAction);// 参数容器.将配置文件中?后的参数放入params中备用.
		// 判断是否带有参数
		if (params != null && !params.isEmpty()) {
			actionName = actionName.substring(0, actionName.indexOf('?'));// 去掉参数，取正确的action名
			
		}

		while (true) {
			
			if (log.isDebugEnabled()) {
				log.debug("invoke the " + i + " result forward:");
				i++;
			}
			if (null == HandyConfiguration.actionMappings(
					actionName.toUpperCase())) {// 未找到对应action中断执行
				//log.error("do forward,can't find action:" + actionName);
				log.error("执行跳转控制器,但未找到要执行的action控制器:" + actionName);
				break;
			} else {
				// 能找到action对应的actionMapping说明
				if (log.isDebugEnabled()) {
					log.debug("actionName:" + actionName);
				}
				ActionMapping actionMapping = HandyConfiguration.actionMappings(actionName.toUpperCase());
				
				if (actionMapping.getStyle() != HandyConfiguration.ACTION_SYTLE_ACTION) {
					//如果执行转换器后返回的不的控制器或转换器,则报错并退出执行
					log.error("请检查返回的类型,当返回类型为<forword>时,定义的结果应该为转换器或者是控制器");
					break;
				}
				if (null != params){
					//将配置文件中要传的参数的整合到ActionForm中
					Set<Entry<String, String>> _params = params.entrySet();
					for (Map.Entry<String, String> entry : _params) {
						String[] values = {entry.getValue()};
						actionForm.getFormMap().put(entry.getKey(), values);
					}
				}
				
				//root.put("actionMapping", actionMapping);//将本次用户请求的action信息注入到管道中所有action中(如果该action中定义了actionMapping变量)
				
//				log.info("==="+((ActionMapping)root.get("actionMapping")).getActionName());
				
				// 请求通过拦截器,将拦截器与该次请求的控制器组成管道让用户请求通过。
				HashMap iMap = null;
				LinkedList<ActionMapping> interceptorMappings = new LinkedList<ActionMapping>();
				if (HandyConfiguration.interceptorMappings(
						actionMapping.getActionPackage()) != null && !HandyConfiguration.interceptorMappings(
								actionMapping.getActionPackage()).isEmpty()) {
//					log.info("存在拦截器");
					interceptorMappings.addAll(HandyConfiguration.interceptorMappings(
							actionMapping.getActionPackage()));// 控制器所在包的所有拦截器
					iMap = doInterceptor(actionMapping,actionForm,root,interceptorMappings);
					if (null == iMap){
						break;//如果未通过拦截器,则中断执行过程,视图会由拦截器返回给请求者
					}
				}
				
				//通过拦截器后,执行本次请求的action控制器.
				AbstractAction action = null;
				try {
					Class<AbstractAction> c = (Class<AbstractAction>) Class
							.forName(actionMapping.getActionClass());
					action = c.newInstance();
					action.setActionMapping(actionMapping);
				} catch (ClassNotFoundException e) {
					log.error(e.getMessage());
				} catch (InstantiationException e) {
					log.error(e.getMessage());
				} catch (IllegalAccessException e) {
					log.error(e.getMessage());
				}
				if (action == null) {
					//log.error("can't find class:" + actionMapping.getActionClass());
					log.error("未找到 控制器 class:" + actionMapping.getActionClass() + " ,请检查类名是否拼写正确!");
					break;
				}
				if (HandyConfiguration.autoHandleParam()) {// 自动将form中的数据装载到action中。
					try {
						BeanUtils.populate(action, actionForm.getFormMap());
					} catch (IllegalAccessException e) {
						log.error(e.getMessage());
					} catch (InvocationTargetException e) {
						log.error(e.getMessage());
					}
				} else {
					action.getForm(actionForm);
				}
				// 将session装载到action中
				action.setSession(request.getSession());
				if (log.isDebugEnabled()){
					log.debug("将session传送到action中");
				}
				// 将request装载到action中
				action.setRequest(request);
				if (log.isDebugEnabled()){
					log.debug("将request传送到action中");
				}
				
				action.setResponse(response);
				if (log.isDebugEnabled()){
					log.debug("将response传送到action中");
				}
				
				action.setContext(context);
				if (log.isDebugEnabled()){
					log.debug("将context传送到action中");
				}
				// 将iMap(拦截器中要传入action的值)中的值填充到action中
				if (iMap != null && !iMap.isEmpty()) {
					try {
						BeanUtils.populate(action, iMap);
					} catch (IllegalAccessException e) {
						log.error(e.getMessage());
					} catch (InvocationTargetException e) {
						log.error(e.getMessage());
					}
				}
				
				if (log.isDebugEnabled()){
					log.debug("开始执行action.execute()方法。");
				}
				

				actionMessage = action.validate(actionMessage);// 执行action自身的验证
				if (null == actionMessage || actionMessage.isEmpty()) {
					result = actionMapping.getActionResults().get(
							action.execute().toUpperCase());
				} else {
					result = actionMapping.getActionResults().get("INPUT");//action自身的验证失败则返回到action定义的INPUT视图
				}
				
				String resultString = result.getResultValue();
				//当返回的是一个静态文件时
				if (resultString != null && !"".equals(resultString)) {
					if (AbstractAction.HANDY_STATIC_FILE
							.equalsIgnoreCase(resultString)) {
						new StaticFile(request, response, context)
								.doStaticFile(action);
						return;
					}else if (AbstractAction.HANDY_ACTION_RESPONSE.equalsIgnoreCase(resultString)){
						return;
					}
				}

				// 处理结果装入root中。
				if (HandyConfiguration.autoHandleParam()) {// 自动将action的get,set字段装载到root中，在视图中显示。
					try {
						root.putAll(PropertyUtils.describe(action));
					} catch (IllegalAccessException e) {
						log.error(e.getMessage());
					} catch (InvocationTargetException e) {
						log.error(e.getMessage());
					} catch (NoSuchMethodException e) {
						log.error(e.getMessage());
					}
				} else {
					HashMap _root = action.sendData();
					if (_root != null)
						root.putAll(_root);
				}

				if (null == result) {// 未找到ActionResult,放弃。
					//log.error("can not find result");
					log.error("没有找到对应的result:"+result+",请检查"+actionMapping.getActionName()+"的配置文件.");
					break;
				}

				if (result.getResultType() == null
						|| result.getResultType().equals("")) {// 默认
					new Default(request, response, context).doDefault(
							actionMapping, action, result.getResultValue());
					break;
				} else if (result.getResultType().equalsIgnoreCase(
						HandyConfiguration.RESULT_FREEMARKER)) {// freemarker
					new FreeMarker(request, response, context).doFreeMarker(
							actionMapping,action,result.getContentType(), result.getResultValue(), root);
					break;
				} else if (result.getResultType().equalsIgnoreCase( 
						HandyConfiguration.RESULT_REDIRECT)) {// redirect
					new Redirect(request, response).doRedirect(action, result
							.getResultValue());
					break;
				} else if (result.getResultType().equalsIgnoreCase(
						HandyConfiguration.RESULT_FORWARD)) {// 如果为forward，则继续循环调用。
					if (params != null) {
						params.clear();
					}
					actionName = result.getResultValue();// 将下一个待处理的action传给actionName
					params = handleParam(actionName, fAction);// 参数容器
					// 判断是否带有参数
					if (params != null && !params.isEmpty()) {
						actionName = actionName.substring(0, actionName
								.indexOf('?'));// 去掉参数，取正确的action名
					}
				}

			}
		}
		if (log.isDebugEnabled()){
			log.info("Forward完成。");
		}
	}

	/**
	 * 处理带参数的action链接，把带$的变量替换成实际的值.
	 * 
	 * @param actionName
	 * @param action
	 * @return
	 */
	private HashMap<String, String> handleParam(String actionName,
			AbstractAction action) {
		if (actionName.indexOf('?') == -1)
			return null;

		HashMap<String, String> params = new HashMap<String, String>();// 参数容器

		// 处理参数
		String _temp = actionName.substring(actionName.indexOf('?') + 1);
		String[] temps = _temp.split("&");
		for (String temp : temps) {
			String[] values = temp.split("=");
			if (values.length != 2)
				continue;// 是否为键值对

			String _value = values[1];
			if (_value.startsWith("$")) {// 为变量
				_value = _value.substring(1);
				if (null != _value && !"".equals(_value)) {
					try {
						params.put(values[0], BeanUtils.getProperty(action,
								_value));
					} catch (IllegalAccessException e) {
						log.error(e.getMessage());
					} catch (InvocationTargetException e) {
						log.error(e.getMessage());
					} catch (NoSuchMethodException e) {
						log.error(e.getMessage());
					}
				}
			} else {// 如果为常量
				params.put(values[0], _value);
			}
		}
		return params;
	}
	
	/**
	 * 执行控制器上的拦截器。
	 * @param actionMapping action描述
	 * @param actionForm 由页面传递过来的参数
	 * @param root 由action传递过来的参数,将注入到拦截器中 
	 * @param interceptorMappings action所在包的所有拦截器
	 * @return
	 */
	@SuppressWarnings("unchecked")
	private HashMap doInterceptor(ActionMapping actionMapping,ActionForm actionForm,HashMap root,LinkedList<ActionMapping> interceptorMappings){
		HashMap map = new HashMap();//保存拦截器中的要传入action控制器的所有参数
		//执行该action所在包的拦截器
		for (ActionMapping interceptorMapping : interceptorMappings) {
			if (log.isDebugEnabled()){
				log.debug("处理拦截器："+interceptorMapping.getActionClass());
			}
			
			//拦截器其实就是action控制器的一种.
			AbstractAction interceptor = null;
			try {
				Class<AbstractAction> c = (Class<AbstractAction>) Class
						.forName(interceptorMapping.getActionClass());
				interceptor = c.newInstance();
				interceptor.setActionMapping(actionMapping);//拦截器里的actionMapping不是本身的描述，而是最下层的action控制器的描述。
			} catch (ClassNotFoundException e) {
				log.error(e.getMessage());
			} catch (InstantiationException e) {
				log.error(e.getMessage());
			} catch (IllegalAccessException e) {
				log.error(e.getMessage());
			}
			if (interceptor == null) {
				//log.error("can't find class:" + actionMapping.getActionClass());
				log.error("未找到 拦截器 class:" + interceptorMapping.getActionClass() + " ,请检查类名是否拼写正确!");
				break;
			}
			
			//装载form参数
			if (HandyConfiguration.autoHandleParam()) {// 自动将form中的数据装载到action中。
				try {
					BeanUtils.populate(interceptor, actionForm.getFormMap());
				} catch (IllegalAccessException e) {
					log.error(e.getMessage());
				} catch (InvocationTargetException e) {
					log.error(e.getMessage());
				}
			} else {
				interceptor.getForm(actionForm);
			}
			// 将session装载到action中
			interceptor.setSession(request.getSession());
			if (log.isDebugEnabled()){
				log.debug("将session传送到action中");
			}
			// 将request装载到action中
			interceptor.setRequest(request);
			if (log.isDebugEnabled()){
				log.debug("将request传送到action中");
			}
			
			interceptor.setResponse(response);
			if (log.isDebugEnabled()){
				log.debug("将response传送到action中");
			}
			
			interceptor.setContext(context);
			if (log.isDebugEnabled()){
				log.debug("将context传送到action中");
			}
			// 将map中的值注入action
			if (root != null && !root.isEmpty()) {
				try {
					BeanUtils.populate(interceptor, root);
				} catch (IllegalAccessException e) {
					log.error(e.getMessage());
				} catch (InvocationTargetException e) {
					log.error(e.getMessage());
				}
			}
			
			if (log.isDebugEnabled()){
				log.debug("开始执行action.execute()方法。");
			}
			
			// 执行action,取返回值。
			String resultString = interceptor.execute();
			
			if (resultString.equalsIgnoreCase("success")) {
				// 拦截器返回success才进入下一个拦截器或最终控制器。
				try {
					map.putAll(PropertyUtils.describe(interceptor));//将拦截器的所有参数装入map备用
				} catch (IllegalAccessException e) {
					log.error(e.getMessage());
				} catch (InvocationTargetException e) {
					log.error(e.getMessage());
				} catch (NoSuchMethodException e) {
					log.error(e.getMessage());
				}
				continue;// 拦截器返回success,运行下一个action
			}else{
				ActionResult result = interceptorMapping.getActionResults().get(resultString.toUpperCase());
				if (result.getResultType() == null
						|| result.getResultType().equals("")) {// 默认
					new Default(request, response, context).doDefault(
							interceptorMapping, interceptor, result.getResultValue());
					map = null;//将map置为空，控制上一级forward结束。
					break;
				} else if (result.getResultType().equalsIgnoreCase(
						HandyConfiguration.RESULT_FREEMARKER)) {// freemarker
					new FreeMarker(request, response, context).doFreeMarker(
							interceptorMapping,interceptor, result.getContentType(),result.getResultValue(), map);
					map = null;
					break;
				}
			}
		}
		return map;
	}

	public HttpServletRequest getRequest() {
		return request;
	}

	public void setRequest(HttpServletRequest request) {
		this.request = request;
	}

	public HttpServletResponse getResponse() {
		return response;
	}

	public void setResponse(HttpServletResponse response) {
		this.response = response;
	}
}
